<template>
  <a-drawer
    v-model:open="open"
    v-model:title="title"
    placement="right"
    width="618"
  >
    <div>
      <a-form
        layout="vertical"
        :model="formRole"
        :rules="rules"
        ref="formRoleRef"
      >
        <a-form-item label="角色名称" name="roleName">
          <a-input
            v-model:value="formRole.roleName"
            placeholder="请输入"
            :maxlength="32"
          />
        </a-form-item>
        <a-form-item label="角色描述" name="roleDesc">
          <a-textarea
            v-model:value="formRole.roleDesc"
            :rows="4"
            :maxlength="500"
            placeholder="请输入(选填)"
          />
        </a-form-item>
        <a-form-item label="权限配置" required>
          <div class="content">
            <a-table
              :columns="columns"
              :data-source="tree"
              bordered
              sticky
              size="middle"
              :expandRowByClick="true"
              :pagination="false"
              :row-key="record => record.id"
              :scroll="{ x: 570 }"
              :loading="loading"
              v-if="tree && tree.length > 0"
            >
              <template #summary>
                <a-table-summary>
                  <a-table-summary-row>
                    <a-table-summary-cell>
                      <div class="role-table-cell">
                        <a-space>
                          <span>全部</span>
                        </a-space>
                        <a-space>
                          <a-checkbox
                            v-model:checked="roleState.dataCheckAll"
                            :indeterminate="roleState.dataAllIndeterminate"
                            @change="onCheckAllChange"
                          ></a-checkbox
                        ></a-space>
                      </div>
                    </a-table-summary-cell>
                    <a-table-summary-cell
                      v-for="(auth, index) in functionalAuthKeys"
                      :key="index"
                      style="text-align: center"
                    >
                      <a-checkbox
                        :disabled="!roleState.dataCheckAll"
                        v-model:checked="roleState[`${auth}CheckAll`]"
                        :indeterminate="roleState[`${auth}AllIndeterminate`]"
                        @change="onCheckAllFunctionalChange(auth)"
                      />
                    </a-table-summary-cell>
                  </a-table-summary-row>
                </a-table-summary>
              </template>
              <template #bodyCell="{ column = {}, record }">
                <template v-if="column.key === 'dataAuth'">
                  <div class="role-table-cell">
                    <a-space>
                      <span>{{ record.fileName }}</span>
                    </a-space>
                    <a-space>
                      <a-checkbox
                        v-model:checked="record.dataAuth.data"
                        :indeterminate="record.dataAuth.dataIndeterminate"
                        @click.stop
                        @change="
                          onCheckDataAuthChange(record, record.dataAuth.data)
                        "
                      ></a-checkbox
                    ></a-space>
                  </div>
                </template>
                <template v-else-if="functionalAuthKeys.includes(column.key)">
                  <a-checkbox
                    v-model:checked="record.permission[column.key]"
                    :indeterminate="
                      record.permission[`${column.key}Indeterminate`]
                    "
                    :disabled="!record.dataAuth.data"
                    @click.stop
                    @change="
                      onCheckfunctionalAuthChange(
                        record,
                        record.permission[column.key],
                        column.key,
                      )
                    "
                  >
                  </a-checkbox>
                </template>
              </template>
            </a-table>
            <div
              v-else
              style="
                display: flex;
                justify-content: center;
                align-items: center;
                height: 100%;
              "
            >
              <a-spin :spinning="loading">
                <a-empty
                  :image="notData"
                  :description="loading ? '加载中...' : '暂无数据'"
                />
              </a-spin>
            </div>
          </div>
        </a-form-item>
      </a-form>
    </div>
    <template #footer>
      <div style="text-align: right">
        <a-button style="margin-right: 8px" @click="onClose">取消</a-button>
        <a-button type="primary" @click="onConfirm"> 确定 </a-button>
      </div>
    </template>
  </a-drawer>
</template>
<script setup>
import { reactive, ref, onMounted, watch } from 'vue'
import { useVModel } from '@vueuse/core'
import { message } from 'ant-design-vue'
import { getRole, getRoleTemplate } from '@/api/role.js'
import notData from '@/assets/images/not-data.png'
/**
 * 外部参数
 */
let props = defineProps({
  open: { type: Boolean, default: () => true },
  title: {
    type: String,
    default() {
      return ''
    },
  },
  contextData: { type: Object, default: () => {} },
})
/**
 * 事件定义
 */
let emit = defineEmits(['update:open', 'update:title', 'edit', 'save'])
/**
 * 双向绑定
 */
let open = useVModel(props, 'open', emit)
let title = useVModel(props, 'title', emit)
let formRoleRef = ref()
let expandedRowKeys = ref([])
let loading = ref(false)
let formRole = reactive({
  roleName: undefined,
  roleDesc: undefined,
})
const columns = [
  {
    title: '数据权限',
    dataIndex: 'dataAuth',
    key: 'dataAuth',
    fixed: 'left',
    width: 200,
  },
  {
    title: '功能权限',
    dataIndex: 'functionalAuth',
    key: 'functionalAuth',
    children: [
      {
        title: '编辑',
        dataIndex: 'edit',
        key: 'edit',
        align: 'center',
        width: 60,
      },
      {
        title: '移动/复制',
        dataIndex: 'move',
        key: 'move',
        align: 'center',
        width: 88,
      },
      {
        title: '废除',
        dataIndex: 'delete',
        key: 'delete',
        align: 'center',
        width: 60,
      },
      {
        title: '上传',
        dataIndex: 'upload',
        key: 'upload',
        align: 'center',
        width: 60,
      },

      {
        title: '下载',
        dataIndex: 'download',
        key: 'download',
        align: 'center',
        width: 60,
      },
      {
        title: '导入',
        dataIndex: 'import',
        key: 'import',
        align: 'center',
        width: 60,
      },
      {
        title: '导出',
        dataIndex: 'export',
        key: 'export',
        align: 'center',
        width: 60,
      },
      {
        title: '预览',
        dataIndex: 'preview',
        key: 'preview',
        align: 'center',
        width: 60,
      },
    ],
  },
]

// 定义所有功能权限的键值
const functionalAuthKeys = [
  'edit',
  'move',
  'delete',
  'upload',
  'download',
  'import',
  'export',
  'preview',
]
// 全部选择
const roleState = reactive({
  indeterminate: false,
  checkAll: false,
  dataCheckAll: false,
  dataAllIndeterminate: false,
  uploadCheckAll: false,
  uploadAllIndeterminate: false,
  copyCheckAll: false,
  copyAllIndeterminate: false,
  downloadCheckAll: false,
  downloadAllIndeterminate: false,
  deleteCheckAll: false,
  deleteAllIndeterminate: false,
})
//校验规则
let rules = {
  roleName: [
    {
      required: true,
      message: '此项为必填项',
      trigger: 'change',
    },
    {
      pattern: /^[\u4e00-\u9fa5a-zA-Z0-9]+$/,
      message: '输入不合理',
      change: 'change',
    },
  ],
}
// 查看选项
let tree = ref([])
// 重置roleState
function resetRoleState() {
  for (let key in roleState) {
    if (roleState.hasOwnProperty(key)) {
      roleState[key] = false
    }
  }
}
watch(
  () => props.contextData,
  contextData => {
    tree.value = []
    if (contextData.btnType === 'edit') {
      formRole.roleName = contextData.data.roleName
      formRole.roleDesc = contextData.data.roleDesc
      loading.value = true
      expandedRowKeys.value = []
      getRole(contextData.data.roleId).then(res => {
        if (res.data && res.data.data) {
          tree.value = JSON.parse(JSON.stringify(res.data.data))
          tree.value.forEach(node => cleanEmptyChildren(node))
          // 给权限添加indeterminate
          tree.value.forEach(node => updateIndeterminateFlags(node))
          //设置数据权限全选的状态
          updateCheckAll(tree.value, 'dataAuth', 'data')
          functionalAuthKeys.forEach(e => {
            updateCheckAll(tree.value, 'permission', e)
          })
          loading.value = false
        }
      })
    } else if (contextData.btnType === 'add') {
      loading.value = true
      getRoleTemplate()
        .then(res => {
          tree.value = res?.data?.data
          tree.value.forEach(node => cleanEmptyChildren(node))
          loading.value = false
        })
        .catch(e => {
          loading.value = false
        })
    }
  },
  { deep: true, immediate: true },
)
// 递归地清理单个树结构中的空children
function cleanEmptyChildren(node) {
  if (Array.isArray(node.children) && node.children.length === 0) {
    delete node.children
  } else if (node.children && node.children.length > 0) {
    for (let i = 0; i < node.children.length; i++) {
      cleanEmptyChildren(node.children[i])
    }

    // 再次检查是否为空数组，因为子节点可能已经被删除
    if (node.children.length === 0) {
      delete node.children
    }
  }
}
// 递归地清理单个树结构中的指定字段
function cleanTree(node) {
  // 删除 parent 字段
  if (node.parent !== undefined) {
    delete node.parent
  }
  // 删除 dataAuth 中的 dataIndeterminate 字段
  if (node.dataAuth && 'dataIndeterminate' in node.dataAuth) {
    delete node.dataAuth.dataIndeterminate
  }
  // 删除 functionalAuth 中的所有 Indeterminate 字段
  if (node.permission) {
    Object.keys(node.permission).forEach(key => {
      if (key.endsWith('Indeterminate')) {
        delete node.permission[key]
      }
    })
  }
  // 递归处理子节点
  if (Array.isArray(node.children)) {
    for (const child of node.children) {
      cleanTree(child)
    }
  }
}
// 清理多棵树结构
function cleanMultipleTrees(trees) {
  trees.forEach(tree => {
    cleanTree(tree)
  })
}
/**
 *  数据权限全选操作
 */
function onCheckAllChange() {
  if (roleState.dataCheckAll) {
    roleState.dataAllIndeterminate = false
    setAllCheckTrue(tree.value, 'dataAuth', 'data', true)
  } else {
    // 取消所有数据权限勾选
    roleState.dataAllIndeterminate = false
    setAllCheckTrue(tree.value, 'dataAuth', 'data', false)
    // 取消所有有功能权限勾选
    functionalAuthKeys.forEach(e => {
      roleState[`${e}AllIndeterminate`] = false
      roleState[`${e}CheckAll`] = false
      setAllCheckTrue(tree.value, 'permission', e, false)
    })
  }
}
/**
 *  功能权限全选操作
 */
function onCheckAllFunctionalChange(auth) {
  if (roleState[`${auth}CheckAll`]) {
    roleState[`${auth}AllIndeterminate`] = false
    setAllCheckTrue(tree.value, 'permission', auth, true)
  } else {
    roleState[`${auth}AllIndeterminate`] = false
    setAllCheckTrue(tree.value, 'permission', auth, false)
  }
}
/**
 * 设置全部权限的check和indeterminate的值
 * @param tree 树结构数据
 * @param  auth 权限
 * @param key 权限里分类
 * @param  value 设置的值为true或false
 */
function setAllCheckTrue(tree, auth, key, value) {
  tree.forEach(node => {
    node[auth][key] = value
    node[auth][`${key}Indeterminate`] = false
    if (node.children && Array.isArray(node.children)) {
      setAllCheckTrue(node.children, auth, key, value) // 递归处理子节点
    }
  })
}
/**
 * 数据权限勾选操作
 */
function onCheckDataAuthChange(row, selected) {
  // 初始化父节点引用
  buildParentReferences(tree.value)
  handleDataAuthSelectionChange(
    tree.value,
    row.id,
    selected,
    'dataAuth',
    'data',
  )

  // 更新全部的勾选状态
  updateCheckAll(tree.value, 'dataAuth', 'data')
  // 数据权限取消勾选
  if (!selected) {
    functionalAuthKeys.forEach(e => {
      handleDataAuthSelectionChange(
        tree.value,
        row.id,
        selected,
        'permission',
        e,
      )
      // 更新全部的勾选状态
      updateCheckAll(tree.value, 'permission', e)
    })
  }
}
// 更新全部勾选的状态
function updateCheckAll(tree, auth, key) {
  let flag = checkAllStatus(tree, auth, key)
  if (flag === 1) {
    roleState[`${key}CheckAll`] = true
    roleState[`${key}AllIndeterminate`] = false
  } else if (flag === 2) {
    roleState[`${key}CheckAll`] = false
    roleState[`${key}AllIndeterminate`] = false
  } else if (flag === 3) {
    roleState[`${key}CheckAll`] = false
    roleState[`${key}AllIndeterminate`] = true
  }
}
/**
 * 功能权限勾选操作
 */
function onCheckfunctionalAuthChange(row, selected, funKey) {
  // 初始化父节点引用
  buildParentReferences(tree.value)
  // 选中节点的级联操作
  handleDataAuthSelectionChange(
    tree.value,
    row.id,
    selected,
    'permission',
    funKey,
  )
  // 更新全部的勾选状态
  updateCheckAll(tree.value, 'permission', funKey)
}
/**
 * 确定所有节点的check的状态
 * @return 1 所有节点的Check值都为true
 * @return 2 所有节点的dataAuthCheck值都为false
 * @return 3 至少有一个节点的dataAuthCheck为true
 * @param tree 树结构数据
 * @param  auth 权限
 * @param key 权限里分类
 */
function checkAllStatus(tree, auth, key) {
  const allTrue = tree.every(
    node =>
      node[auth][key] &&
      (!node.children ||
        node.children.every(child => checkAllStatus([child], auth, key) === 1)),
  )
  const atLeastOneTrue = tree.some(
    node =>
      node[auth][key] ||
      (node.children &&
        node.children.some(child => checkAllStatus([child], auth, key) !== 2)),
  )

  if (allTrue) {
    return 1
  } else if (atLeastOneTrue) {
    return 3
  } else {
    return 2
  }
}

/**
 * 重置form表单
 */
function resetForm() {
  formRoleRef.value.resetFields()
}

// 更新指定节点及其所有子孙节点的 dataAuth.data 为 selected
function updateAllChildrenDataAuth(node, selected, auth, key) {
  node[auth][key] = selected
  node[auth][`${key}Indeterminate`] = false
  if (Array.isArray(node.children)) {
    for (const child of node.children) {
      updateAllChildrenDataAuth(child, selected, auth, key)
    }
  }
}
// 更新指定节点的所有祖先节点的 dataAuth.data 和 dataIndeterminate 状态
function updateParentDataAuth(node, auth, key) {
  let parent = node.parent
  while (parent) {
    let allChildrenSelected = true
    let someChildrenSelected = false

    if (Array.isArray(parent.children)) {
      for (const child of parent.children) {
        if (child[auth][key]) {
          someChildrenSelected = true
        } else {
          allChildrenSelected = false
        }
        if (child[auth][`${key}Indeterminate`]) {
          allChildrenSelected = false
          someChildrenSelected = true
        }
      }
      parent[auth][key] = allChildrenSelected
      parent[auth][`${key}Indeterminate`] =
        someChildrenSelected && !allChildrenSelected
    }

    parent = parent.parent // 继续更新更上层的祖先节点
  }
}

// 处理节点 dataAuth 的选择变化
function handleDataAuthSelectionChange(tree, nodeId, selected, auth, key) {
  // 找到目标节点并更新其选择状态
  function findNodeAndUpdateSelection(node, id, selected) {
    if (node.id === id) {
      if (selected) {
        updateAllChildrenDataAuth(node, true, auth, key) // 如果是选中，则级联选中所有子节点
      } else {
        updateAllChildrenDataAuth(node, false, auth, key)
        node[auth][key] = false
        node[auth][`${key}Indeterminate`] = false
      }
      return true
    }
    if (Array.isArray(node.children)) {
      for (const child of node.children) {
        if (findNodeAndUpdateSelection(child, id, selected)) {
          return true
        }
      }
    }
    return false
  }
  // 遍历所有顶级节点，找到目标节点并更新其选择状态
  for (const rootNode of tree) {
    if (findNodeAndUpdateSelection(rootNode, nodeId, selected)) {
      break
    }
  }
  // 再次遍历所有顶级节点，更新所有祖先节点的选择状态
  function traverseAndUpdateParents(node) {
    if (node.id === nodeId) {
      updateParentDataAuth(node, auth, key)
      return
    }

    if (Array.isArray(node.children)) {
      for (const child of node.children) {
        traverseAndUpdateParents(child)
      }
    }
  }
  for (const rootNode of tree) {
    traverseAndUpdateParents(rootNode)
  }
}
// 建立父子关系引用，以便更容易更新祖先节点
function buildParentReferences(tree) {
  function traverse(node, parent = null) {
    node.parent = parent

    if (Array.isArray(node.children)) {
      for (const child of node.children) {
        traverse(child, node)
      }
    }
  }

  for (const rootNode of tree) {
    traverse(rootNode)
  }
}
/**
 * 校验是否配置了权限
 */
function validatePermission(nodes) {
  // 如果传入的是单个节点，则放入数组中统一处理
  if (!Array.isArray(nodes)) {
    nodes = [nodes]
  }
  for (const node of nodes) {
    if (node.dataAuth && node.dataAuth.data === true) {
      return true
    }
    // 如果有子节点，则递归检查子节点
    if (Array.isArray(node.children) && node.children.length > 0) {
      if (validatePermission(node.children)) {
        return true
      }
    }
  }
  return false
}
/**
 * 确定操作
 */
async function onConfirm() {
  if (open.value) {
    formRoleRef.value
      .validate()
      .then(() => {
        let flag = validatePermission(tree.value)
        if (!flag) {
          message.error('请配置权限')
          return
        }
        cleanMultipleTrees(tree.value)
        let params = {
          roleName: formRole.roleName,
          roleDesc: formRole.roleDesc,
          data: tree.value,
        }
        if (props.contextData.btnType === 'edit') {
          params.roleId = props.contextData.data.roleId
          emit('edit', params)
        } else {
          emit('save', params)
        }
        tree.value = []
        resetForm()
        resetRoleState()
        open.value = false
      })
      .catch(() => {})
  }
}
/**
 * 取消操作
 */
function onClose() {
  open.value = false
  resetForm()
  resetRoleState()
  tree.value = []
}
/**
 * 给权限都添加indeterminate
 */
function updateIndeterminateFlags(node) {
  // 初始化 dataAuth 的 dataIndeterminate 字段
  node.dataAuth.dataIndeterminate = false

  // 初始化 permission 中每个权限的 indeterminate 字段
  const permissionKeys = Object.keys(node.permission)
  permissionKeys.forEach(key => {
    node.permission[key + 'Indeterminate'] = false
  })

  if (node.children && node.children.length > 0) {
    let hasDataTrue = false
    let allDataFalse = true
    let allDataTrue = true

    const permissionHasTrue = {}
    const allPermissionsFalse = {}
    const allPermissionsTrue = {}

    permissionKeys.forEach(key => {
      permissionHasTrue[key] = false
      allPermissionsFalse[key] = true
      allPermissionsTrue[key] = true
    })

    for (const child of node.children) {
      updateIndeterminateFlags(child) // 递归处理子节点

      if (child.dataAuth.data || child.dataAuth.dataIndeterminate) {
        hasDataTrue = true
      }
      if (child.dataAuth.data) {
        allDataFalse = false
      } else {
        allDataTrue = false
      }

      permissionKeys.forEach(key => {
        if (child.permission[key] || child.permission[key + 'Indeterminate']) {
          permissionHasTrue[key] = true
        }
        if (child.permission[key]) {
          allPermissionsFalse[key] = false
        } else {
          allPermissionsTrue[key] = false
        }
      })
    }

    // 如果所有子节点的 dataAuth.data 都为 false，当前节点的 dataAuth.data 也设为 false
    if (allDataFalse) {
      node.dataAuth.data = false
    }
    if (allDataTrue) {
      node.dataAuth.data = true
      node.dataAuth.dataIndeterminate = false
    } else if (hasDataTrue) {
      node.dataAuth.dataIndeterminate = hasDataTrue
      node.dataAuth.data = false
    }
    permissionKeys.forEach(key => {
      if (allPermissionsFalse[key]) {
        node.permission[key] = false
      }
      if (allPermissionsTrue[key]) {
        node.permission[key] = true
        node.permission[key + 'Indeterminate'] = false
      } else if (permissionHasTrue[key]) {
        node.permission[key + 'Indeterminate'] = true
        node.permission[key] = false
      }
    })
  }
  return node
}
</script>
<style lang="less" scoped>
.content {
  overflow-y: hidden;
}
.ant-form-item :deep(.ant-form-item-label) {
  text-align: left;
}
:global(.ant-table-summary) {
  display: table-header-group;
  background-color: #fff;
  scroll-behavior: none;
}
.role-table-cell {
  display: flex;
  justify-content: space-between;
}
.ant-form :deep(.ant-form-item:last-child) {
  margin-bottom: 0 !important;
}
.ant-table-summary > tr > td:first-child {
  position: sticky;
  left: 0;
  background-color: #fff;
  z-index: 10; /* 确保足够高 */
}
</style>
